"""存储游戏中的各种方法的文件"""

import sys
import time
from time import sleep

import pygame
from bullet import Bullet
from enemy import Enemy


def check_keydown_events(event, settings, screen, sound, spacecraft, bullets):
    """响应按键"""
    if event.key == pygame.K_d or event.key == pygame.K_RIGHT:
        spacecraft.moving_right = True
    elif event.key == pygame.K_a or event.key == pygame.K_LEFT:
        spacecraft.moving_left = True
    elif event.key == pygame.K_w or event.key == pygame.K_UP:
        spacecraft.moving_front = True
    elif event.key == pygame.K_s or event.key == pygame.K_DOWN:
        spacecraft.moving_back = True
    elif event.key == pygame.K_SPACE:
        fire(settings, screen, sound, spacecraft, bullets)
    elif event.key == pygame.K_ESCAPE:
        sys.exit()


def fire(settings, screen, sound, spacecraft, bullets):
    # 如果子弹数量没有超出限制，就创建一颗子弹，并将其加入到编组bullets里去
    if len(bullets) < settings.bullets_allowed:
        new_bullet = Bullet(settings, screen, spacecraft)
        bullets.add(new_bullet)
        # 播放发射子弹的音效
        sound.play_launch_bullet_sound()


def check_keyup_events(event, spacecraft):
    """响应松开"""
    if event.key == pygame.K_d or event.key == pygame.K_RIGHT:
        spacecraft.moving_right = False
    elif event.key == pygame.K_a or event.key == pygame.K_LEFT:
        spacecraft.moving_left = False
    elif event.key == pygame.K_w or event.key == pygame.K_UP:
        spacecraft.moving_front = False
    elif event.key == pygame.K_s or event.key == pygame.K_DOWN:
        spacecraft.moving_back = False


def check_events(settings, screen, stats, play_button, sb, sound, spacecraft, enemies, bullets):
    """响应键盘和鼠标事件"""
    # 监视键盘和鼠标事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, settings, screen, sound, spacecraft, bullets)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, spacecraft)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(settings, screen, stats, play_button, sb, spacecraft,
                              enemies, bullets, mouse_x, mouse_y)


def check_play_button(settings, screen, stats, play_button, sb, spacecraft, enemies,
                      bullets, mouse_x, mouse_y):
    """在玩家单机Play按钮时开始新游戏"""
    button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
    if button_clicked and not stats.dictionaries['active']['game_active']:
        # 重置游戏
        settings.initialize_dynamic_settings()

        # 隐藏胜利信息
        stats.dictionaries['active']['win_str_active'] = False

        # 隐藏失败信息
        stats.dictionaries['active']['lost_str_active'] = False

        # 激活新纪录音效
        stats.dictionaries['active']['new_record_sound'] = True

        # 玩游戏次数加一
        stats.play_game_frequency += 1

        # 隐藏鼠标
        pygame.mouse.set_visible(False)

        # 重置游戏统计信息
        stats.reset_stats()
        stats.dictionaries['active']['game_active'] = True

        # 播放背景音乐
        play_background_music(stats)

        # 重置记分牌图像
        sb.prep_score()
        sb.prep_highest_score()
        sb.prep_level()
        sb.prep_spacecraft_mappings()

        # 清空敌人和子弹列表
        enemies.empty()
        bullets.empty()

        # 创造一个新的敌人舰队，并让飞船居中
        create_fleet(settings, screen, spacecraft, enemies)
        spacecraft.reset(settings, screen)


def update_screen(settings, screen, stats, sb, spacecraft, enemies, bullets,
                  play_button, background_picture):
    """更新屏幕的图像，并切换到新屏幕"""
    # 每次循环都重新绘制背景图片
    screen.blit(background_picture, (0, 0))

    # 在飞船和外星人后面重新绘制所有子弹
    for bullet in bullets:
        bullet.draw_bullet()
    spacecraft.draw_spacecraft()
    enemies.draw(screen)

    # 如果处于获胜状态，则显示胜利信息
    if stats.dictionaries['active']['win_str_active']:
        sb.show_win_str()

    # 如果处于失败状态，则显示失败信息
    if stats.dictionaries['active']['lost_str_active']:
        sb.show_lost_str()

    # 显示得分
    sb.show_score()

    # 如果游戏处于非活跃状态，就绘制Play按钮
    if not stats.dictionaries['active']['game_active']:
        play_button.draw_button()

    # 让最近绘制的屏幕可见
    pygame.display.flip()


def update_bullets(settings, screen, stats, sb, sound, spacecraft, enemies, bullets):
    """更新子弹的位置以及删除消失的子弹"""
    # 更新子弹位置
    bullets.update()

    # 删除已消失的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)

    check_bullets_enemies_collisions(settings, screen, stats, sb, sound, spacecraft, enemies, bullets)


def check_bullets_enemies_collisions(settings, screen, stats, sb, sound, spacecraft,
                                     enemies, bullets):
    """响应子弹和敌人的碰撞"""
    # 删除发生碰撞的子弹和外星人
    bullet_enemy_collisions = pygame.sprite.groupcollide(bullets, enemies, True, True)

    if bullet_enemy_collisions:
        for enemies in bullet_enemy_collisions.values():
            sound.play_enemy_blast_sound()
            stats.score += settings.enemy_points * len(enemies)
            sb.prep_score()
            check_highest_score(stats, sb, sound)

    if len(enemies) == 0:
        # 如果整支敌人舰队被消灭，就进入下一个关卡
        bullets.empty()
        settings.increase_speed()

        # 提高等级
        stats.level += 1

        # 若当前关卡大于限制关卡数，则游戏胜利
        if stats.level > settings.game_level_limit:
            sb.show_win_str()
            stats.dictionaries['active']['game_active'] = False
            stats.dictionaries['active']['win_str_active'] = True
            pygame.mouse.set_visible(True)
            # 停止背景音乐播放并播放胜利音乐
            play_background_music(stats)
            play_win_music()
        else:
            sb.prep_level()

            create_fleet(settings, screen, spacecraft, enemies)


def get_number_enemies_x(settings, enemy_width):
    """计算每行可以容纳多少敌人"""
    available_space_x = settings.screen_width - 2 * enemy_width
    number_enemies_x = int(available_space_x / (2 * enemy_width))
    return number_enemies_x


def get_number_rows(settings, spacecraft_height, enemy_height):
    """计算屏幕可容纳多少行外星人"""
    available_space_y = (settings.screen_height - (3 * enemy_height) -
                         spacecraft_height)
    number_rows = int(available_space_y / (2 * enemy_height))
    return number_rows


def create_enemy(settings, screen, enemies, enemy_number, row_number):
    """创建一个敌人并把它放到当前行"""
    enemy = Enemy(settings, screen)
    enemy_width = enemy.rect.width
    enemy.x = enemy_width + 2 * enemy_width * enemy_number
    enemy.rect.x = enemy.x
    enemy.y = enemy.rect.height + 2 * enemy.rect.height * row_number
    enemy.rect.y = enemy.y
    enemies.add(enemy)


def create_fleet(settings, screen, spacecraft, enemies):
    """创建敌人舰队"""
    # 创建一个敌人，并计算一行可以容纳多少个敌人
    enemy = Enemy(settings, screen)
    number_enemies_x = get_number_enemies_x(settings, enemy.rect.width)
    number_rows = get_number_rows(settings, spacecraft.rect.height,
                                  enemy.rect.height)

    # 创建敌人群
    for row_number in range(number_rows):
        for enemy_number in range(number_enemies_x):
            create_enemy(settings, screen, enemies, enemy_number,
                         row_number)


def fleet_boundary_cheeck(settings, enemies):
    """有敌人到达界面边缘时采取相应措施"""
    for enemy in enemies.sprites():
        if enemy.boundary_check():
            change_fleet_direction(settings, enemies)
            break


def change_fleet_direction(settings, enemies):
    """将敌人舰队整行下移，并改变方向"""
    for enemy in enemies.sprites():
        enemy.rect.y += settings.enemy_drop_speed_factor
    settings.fleet_direction *= -1


def spacecraft_hit(settings, screen, stats, sb, sound, spacecraft, enemies, bullets):
    """响应被敌人撞到的飞船"""
    if stats.spacecraft_life > 1:
        # 将飞船生命减1
        stats.spacecraft_life -= 1

        # 更新飞船数
        sb.prep_spacecraft_mappings()

        # 清空敌人编组和子弹编组
        enemies.empty()
        bullets.empty()

        # 创建新的敌人舰队，并将飞船放到初始位置
        create_fleet(settings, screen, spacecraft, enemies)
        spacecraft.reset(settings, screen)

        # 播放飞船爆炸音效
        sound.play_spacecraft_blast_sound()

        # 暂停
        sleep(0.5)

    else:
        # 飞船生命减1，并更新飞船数
        stats.spacecraft_life -= 1
        sb.prep_spacecraft_mappings()

        # 清空敌人
        enemies.empty()

        sound.play_spacecraft_blast_sound()
        stats.dictionaries['active']['game_active'] = False
        stats.dictionaries['active']['lost_str_active'] = True
        pygame.mouse.set_visible(True)

        # 停止播放背景音乐并播放游戏失败音乐
        play_background_music(stats)
        play_lost_music()


def check_fleet_bottom(settings, screen, stats, sb, sound, spacecraft, enemies, bullets):
    """检查是否有敌人到达了屏幕底端"""
    screen_rect = screen.get_rect()
    for enemy in enemies.sprites():
        if enemy.rect.bottom >= screen_rect.bottom:
            # 像飞船被撞到一样处理
            spacecraft_hit(settings, screen, stats, sb, sound, spacecraft, enemies, bullets)
            break


def update_enemies(settings, screen, stats, sb, sound, spacecraft, enemies, bullets):
    """检查是否有敌人位于屏幕边缘，更新敌人舰队中所有敌人的位置"""
    fleet_boundary_cheeck(settings, enemies)
    enemies.update()

    # 检查敌人和飞船的碰撞
    if pygame.sprite.spritecollideany(spacecraft, enemies):
        spacecraft_hit(settings, screen, stats, sb, sound, spacecraft, enemies, bullets)

    # 检查是否有敌人到达屏幕底部
    check_fleet_bottom(settings, screen, stats, sb, sound, spacecraft, enemies, bullets)


def check_highest_score(stats, sb, sound):
    """检查是否诞生了新的最高分"""
    # 如果不是第一次玩游戏，且拿到了新的最高分，则播放最高分音效
    if stats.score > stats.highest_score and stats.play_game_frequency > 1:
        sound.play_new_record_sound(stats)
    # 更新最高分
    if stats.score > stats.highest_score:
        stats.highest_score = stats.score
        sb.prep_highest_score()


def play_background_music(stats):
    """检查游戏是否处于活跃状态，如果是则循环播放背景音乐"""
    pygame.mixer.init()
    pygame.mixer.music.load('images_source/background_music.mp3')
    if stats.dictionaries['active']['game_active']:
        pygame.mixer.music.play(-1, 0)
    else:
        pygame.mixer.music.stop()


def play_win_music():
    """播放游戏胜利音乐"""
    pygame.mixer.init()
    pygame.mixer.music.load('images_source/win_music.mp3')
    pygame.mixer.music.play(1, 0)


def play_lost_music():
    """播放游戏失败音乐"""
    pygame.mixer.init()
    pygame.mixer.music.load('images_source/lost_music.mp3')
    pygame.mixer.music.play(1, 0)



